﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using MahApps.Metro.Controls;
using Microsoft.ClearScript.V8;
using Script.ClearScript_V8;

namespace FrameworkTemplate.Windows
{
    /// <summary>
    /// 脚本管理窗口
    /// </summary>
    public partial class ScriptManagerWindow : MetroWindow
    {
        ScriptManager scriptManager;
        string folder_path;
        Data data;

        class Data : INotifyPropertyChanged
        {
            string log = "";

            public string Log
            {
                get
                {
                    var t = log;
                    log = "";
                    return t;
                }
                set
                {
                    log += value;
                    //Logs.Add( log);
                    NotifyPropertyChanged();
                }
            }

            public event PropertyChangedEventHandler PropertyChanged;
            // This method is called by the Set accessor of each property.
            // The CallerMemberName attribute that is applied to the optional propertyName
            // parameter causes the property name of the caller to be substituted as an argument.
            private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        
        /// <summary>
        /// 脚本管理窗口初始化类
        /// </summary>
        /// <param name="scriptManager">脚本管理类对象</param>
        /// <param name="folder_path">脚本文件夹路径</param>
        public ScriptManagerWindow(ScriptManager scriptManager, string folder_path)
        {
            InitializeComponent();
            this.scriptManager = scriptManager;
            this.folder_path = folder_path;
            data = new Data();

            //绑定菜单命令
            CommandBinding save_as_cmd = new CommandBinding(ApplicationCommands.SaveAs, SaveAsExcuted);
            this.CommandBindings.Add(save_as_cmd);

            //设置数据源
            script_status_grid.ItemsSource = scriptManager.Engines.Values;
            scriptManager.OnLog += ScriptManager_OnLog;//添加日志事件处理方法
            scriptManager.OnError += ScriptManager_OnError;//添加错误事件处理方法
            //绑定数据
            load_progress.SetBinding(ProgressBar.ValueProperty, new Binding { Source = scriptManager, Path = new PropertyPath("Progress")});
            logs.SetBinding(TextBox.DataContextProperty, new Binding { Source = data, Path = new PropertyPath("Log") });

        }

        private void SaveAsExcuted(object sender, ExecutedRoutedEventArgs e)
        {
            Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog
            {
                FileName = DateTime.Now.ToString("yyyyMMdd HH-mm-ss"), // Default file name
                DefaultExt = @".log", // Default file extension
                Filter = "log file (.log)|*.log" // Filter files by extension
            };

            // Show save file dialog box
            Nullable<bool> result = dlg.ShowDialog();

            // Process save file dialog box results
            if (result == true)
            {
                // Save document
                string filename = dlg.FileName;
                File.WriteAllText(filename, ((TextBox)e.Source).Text);
            }
        }

        private void ScriptManager_OnError(Exception e, V8ScriptEngine engine)
        {
            data.Log = DateTime.Now.ToString("[HH:mm:ss]") + engine.Name +
                System.Windows.Application.Current.FindResource("script_onerror") as string 
                + Environment.NewLine + e.ToString() + Environment.NewLine;
        }

        private void ScriptManager_OnLog(string log)
        {
            data.Log = DateTime.Now.ToString("[HH:mm:ss]") + log + Environment.NewLine;
        }
        
        private void Reload_selected_Click(object sender, RoutedEventArgs e)
        {
            ReloadSelected();
        }
        private async void ReloadSelected()
        {
            reload_selected.IsEnabled = false;
            var items = script_status_grid.SelectedItems;
            await Task.Run(() =>
            {
                var scripts = new Dictionary<string, string>();
                foreach (var item in items)
                {
                    var engine = (Engine)item;
                    var file_path = System.IO.Path.Combine(folder_path, engine.ScriptEngine.Name) + ".js";
                    if (File.Exists(file_path))
                        scripts[engine.ScriptEngine.Name] = File.ReadAllText(file_path);
                }
                scriptManager.InterruptScripts(scripts.Keys.ToArray());
                scriptManager.RunScriptTasks(scripts);

            });
            reload_selected.IsEnabled = true;
            script_status_grid.Items.Refresh();
        }

        private async void Stop_selected_Click(object sender, RoutedEventArgs e)
        {
            var scripts = script_status_grid.SelectedItems.Cast<Engine>()
                    .Select(engine => engine.ScriptEngine.Name)
                    .ToArray();
            await Task.Run(() =>
            {
                scriptManager.StopLoading();
                scriptManager.InterruptScripts(scripts);
            });
        }
        
        private void Select_all_Click(object sender, RoutedEventArgs e)
        {
            script_status_grid.SelectAll();
        }

        private void Reload_folder_Click(object sender, RoutedEventArgs e)
        {
            ReloadFolder();
        }
        private async void ReloadFolder()
        {
            reload_folder.IsEnabled = false;
            await Task.Run(() =>
            {
                var scripts = ScriptManager.LoadScripts(folder_path);
                scriptManager.StopLoading();
                scriptManager.InterruptScripts(scriptManager.Engines.Keys.ToArray());
                scriptManager.RunScriptTasks(ScriptManager.LoadScripts(folder_path));

            });
            reload_folder.IsEnabled = true;
            script_status_grid.Items.Refresh();
        }

        private void Logs_TextChanged(object sender, TextChangedEventArgs e)
        {
            logs.ScrollToEnd();
        }

        private void MetroWindow_Closed(object sender, EventArgs e)
        {
            scriptManager.OnLog -= ScriptManager_OnLog;
            scriptManager.OnError -= ScriptManager_OnError;
        }

        private void Logs_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
        {

            if (logs.Text.Length >= 16777216)
                logs.Clear();
            logs.Text += e.NewValue;
        }

        private void Script_status_grid_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            var width = e.NewSize.Width - script_status_grid.Columns[0].MinWidth;
            if(double.IsNaN(width))
                return;
            script_status_grid.Columns[1].Width = width * 0.5;
            script_status_grid.Columns[2].Width = width * 0.5;
        }

        private void Clear_Click(object sender, RoutedEventArgs e)
        {
            logs.Clear();

        }

        private void MenuItem_Click(object sender, RoutedEventArgs e) => System.Diagnostics.Process.Start("Explorer", System.IO.Path.GetFullPath(folder_path));
    }
}